package Tier1;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.rmi.RemoteException;
import java.util.ArrayList;
import java.util.Map.Entry;

import Shared.*;

/**
 * Execute les choix de l'utilisateur pour afficher les différents menu
 * Présentation et affichage de la partie, du classement, des scores, etc.
 * Envoit les actions du client vers le tier 2.
 * 
 */
public class User {
    private static User.Service _service = null;
    private User.Callback _callback = null;
    
    private Player p = null;
    private Party party = null;
    private String login = "", password = "", nb = "";
    private int sousMenu = -1, num = 0;
    
    /**
     * Gère les menu principaux, relaye aux sous-menu les choix
     * (accueil -> login/inscription, play -> creer/rejoindre une partie, etc)
     * @param service
     * @throws RemoteException
     */
    public void run() {

	boolean arret = false;
	int menu = _Config.MENU_ACCUEIL;
	
	while (!arret) {
	    BufferedReader keyboard = new BufferedReader(new InputStreamReader(System.in));
	    switch (menu) {
	    
	    case -1 : arret = true; break;
	    
	    // +----------------------------------------------------------------------+
	    // | menu ACCUEIL
	    // |
	    // | Premier menu : s'identifier ou créer un compte
	    // | Succes : menu LOGIN/CREERUSER
	    // | Echec : menu ACCUEIL
	    // +----------------------------------------------------------------------+
	    case Shared._Config.MENU_ACCUEIL:
		if(sousMenu>0) {
		    menu = menuAccueil();
		    break;
		}
		
		System.out.println("Bonjour, Bienvenue sur le jeu de Bataille\n" +
			"[1] S'identifier\n" +
			"[2] Créer un compte\n" +
			"Faites votre choix : "
		);
		try { nb = keyboard.readLine(); } catch (IOException e) { System.out.println("500 Internal Error"); }
		try {
		    sousMenu = Integer.parseInt(nb);
		    menu = menuAccueil();
		    
		} catch (Exception e) {
		    System.out.println("Veuillez saisir un entier");
		    menu = _Config.MENU_ACCUEIL;
		}
		break;

	    // +----------------------------------------------------------------------+
	    // | menu PLAY
	    // |
	    // | Menu principal des parties
	    // | Succes : ?
	    // | Echec : menu PLAY
	    // +----------------------------------------------------------------------+
	    case _Config.MENU_PLAY:
		if(sousMenu>0) {
		    menu = menuPlay();
		    break;
		}
		
		System.out.println("***Menu Principal***\n" +
			"[1] Créer une partie\n" +
			"[2] Rejoindre une partie\n" +
			"[3] Voir vos Scores\n" +
			"[4] Voir le classement\n" +
			"[5] Quitter\n"
		);
		try { nb = keyboard.readLine(); } catch (IOException e) { System.out.println("500 Internal Error"); }
		try {
		    sousMenu = Integer.parseInt(nb);
		    menu = menuPlay();
		    sousMenu = -1;
			
		} catch (Exception e) {
		    System.out.println("Veuillez saisir un entier");
		    menu = _Config.MENU_PLAY;
		}
		break;
		
	    // +----------------------------------------------------------------------+
	    // | menu PARTY
	    // |
	    // | Menu permettant de jouer
	    // | Succes : ?
            // | Echec : ?
	    // +----------------------------------------------------------------------+	
	    case _Config.MENU_PARTY:
		if(sousMenu>0) {
		    menu = menuParty();
		    break;
		}
		
		System.out.println(
			"[1] Jouer\n" +
			"[2] Abandonner\n"
		);
		try { nb = keyboard.readLine(); } catch (IOException e) { System.out.println("500 Internal Error"); }
		try {
		    sousMenu = Integer.parseInt(nb);
		    menu = menuParty();
		    sousMenu = -1;
			
		} catch (Exception e) {
		    System.out.println("Veuillez saisir un entier");
		    menu = _Config.MENU_PARTY;
		}
		break;
	    default:
		//System.out.println("Attente!");
		break;
	    }
	}
    }
    
    /**
     * menu accueil
     * @return numero du prochain menu à afficher
     * @throws RemoteException
     */
    private int menuAccueil() {
    int menu = _Config.MENU_ACCUEIL;
    try {
	BufferedReader keyboard = new BufferedReader(new InputStreamReader(System.in));
	
	switch (sousMenu) {

        // +----------------------------------------------------------------------+
        // | menu ACCUEIL : MENU_LOGIN
        // |
        // | Demande à l'utilisateur de s'authentifier (user + password)
        // | Succes : menu PLAY
        // | Echec : menu LOGIN
        // +----------------------------------------------------------------------+
        case _Config.MENU_LOGIN:
    
        	System.out.println("***Connexion***");
        	System.out.println("Votre identifiant : "); try { login = keyboard.readLine(); } catch (IOException e) { System.out.println("500 Internal Error"); }
        	System.out.println("Mot de passe : "); try { password = keyboard.readLine(); } catch (IOException e) { System.out.println("500 Internal Error"); }
        
        	if (_service.login(login, password) && !login.isEmpty() && !password.isEmpty()) {
        	    p = _service.getPlayer(this.hashCode() + "", login);
        	    System.out.println("Vous êtes connecté!");
        	    menu = _Config.MENU_PLAY;
        	    sousMenu = -1;
        	} else {
        	    System.out.println("erreur login");
        	    menu = _Config.MENU_ACCUEIL;
        	    sousMenu = -1;
        	}
        	break;
    
        // +----------------------------------------------------------------------+
        // | menu ACCUEIL : CREERUSER
        // |
        // | Demande à l'utilisateur de créer un compte (user + password)
        // | Succes : menu PLAY
        // | Echec : menu CREERUSER
        // +----------------------------------------------------------------------+
        case _Config.MENU_CREERUSER:
    
        	System.out.println("***Création d'un compte***");
        	System.out.println("Identifiant : "); try { login = keyboard.readLine(); } catch (IOException e) { System.out.println("500 Internal Error"); }
        	System.out.println("Mot de passe : "); try { password = keyboard.readLine(); } catch (IOException e) { System.out.println("500 Internal Error"); }
        
        	if (_service.creerCompte(login, password)) {
        		p = _service.getPlayer(this.hashCode() + "", login);
        	    System.out.println("Bravo, Compte créé.");
        	    menu = _Config.MENU_PLAY;
        	    sousMenu = -1;
        	} else {
        	    System.out.println("Erreur, cet identifiant existe déjà veuillez en choisir un autre.");
        	    menu = _Config.MENU_ACCUEIL;
        	    sousMenu = _Config.MENU_CREERUSER;
        	}
        	break;
    
	}
    } catch (RemoteException e) {
	System.out.println("Le serveur est inaccessible ou la requête est erronée");
	e.printStackTrace();
    }
    return menu;
    }

    /**
     * Menu play
     * @return numero du prochain menu à afficher
     * @throws RemoteException
     */
    private int menuPlay() {
    int menu = _Config.MENU_PLAY;
    try {
	BufferedReader keyboard = new BufferedReader(new InputStreamReader(System.in));
	boolean arret = false;
	
	switch (sousMenu) {
	
	// +----------------------------------------------------------------------+
	// | menu PLAY : 1
	// |
	// | Créer une partie
	// +----------------------------------------------------------------------+
	case 1:
		
	    System.out.println("***Créer une partie***");
	    while (!arret) {
		System.out.println("Nombre de joueurs (de 2 à 9 joueurs) : "); try { nb = keyboard.readLine(); } catch (IOException e) { System.out.println("500 Internal Error"); }
		try {
		    num = Integer.parseInt(nb);
		    if(num > 1 && num < 10){
			party = _service.createParty(p, num);
			System.out.println("Partie " + party.get_id() + " créée !\n Attendez d'autres joueurs !\n");
			
			arret = true;
			synchronized(_callback) {
			    _callback.wait();
			}
			menu = _Config.MENU_PARTY;
			
		    } else {
		    	System.out.println("Veuillez saisir un nombre supérieur à 1 et inférieur à 10.");
		    }
		    
		} catch (Exception e) {
			e.printStackTrace();
		    System.out.println("Veuillez saisir un entier");
		}
	    }
	    break;
	    
	// +----------------------------------------------------------------------+
	// | menu PLAY : 2
	// |
	// | Rejoindre une partie
	// +----------------------------------------------------------------------+
	case 2:
		
	    //parties en attente
	    System.out.println("***Listes des parties en attente***");
	    ArrayList<Party> parties = _service.getParties();
		if(parties.size() > 0){
	    	for (Party party : parties) {
			if (party.getStatut() == _Config.PARTY_ATTENTE) {
			    System.out.println("| Partie n° " + party.get_id()+" | "+party.getNbPlayers()+" joueurs dans la partie.");
			    for(Entry<Player, Integer> entry : party.getPlayers().entrySet()){
				System.out.println(entry.getKey().getName());
			    }
			}
		    }
		    
		    //partie à rejoindre
		    //TODO rejoindre la partie et gérer le cas où la partie a démarré entre temps
		    while (!arret) {
			System.out.println("Numéro partie a rejoindre : "); try { nb = keyboard.readLine(); } catch (IOException e) { System.out.println("500 Internal Error"); }
			try {
				if(!nb.isEmpty()){
				    num = Integer.parseInt(nb);
				    if(num != -1 || num > 0){
				    	party = _service.joinParty(num, p);
				    	if(party.get_id() != -1){
				    	    
				    	    	arret = true;
						synchronized(_callback) {
						    _callback.wait();
						}
						menu = _Config.MENU_PARTY;
						
				    	} else { System.out.println("Erreur lors de la connexion à la partie"); }
				    }else if(num==-1){ System.out.println("Retour."); arret = true;}
				    else{ System.out.println("Erreur de saisie"); }
				}
			} catch (Exception e) {
				e.printStackTrace();
			    System.out.println("Veuillez saisir un entier");
			}
		    }
		} else{
			System.out.println("Aucune partie en attente.");
		}
	    break;
	    
	// +----------------------------------------------------------------------+
	// | menu PLAY : 3
	// |
	// | Voir score des (dernieres ?) parties jouées
	// +----------------------------------------------------------------------+
	case 3: //TODO - code temporaire
		System.out.println("***Votre score***");
		System.out.println(p.getScore()+" points.\n");
	    break;
	    
	// +----------------------------------------------------------------------+
	// | menu PLAY : 4
	// |
	// | Voir classement (meilleurs scores)
	// +----------------------------------------------------------------------+
	case 4:
		System.out.println("**Classement***");
		Players classement = _service.getClassement();
		int cpt = 1;
		for(Player p : classement.liste){
			System.out.println("["+cpt+"]"+p.getName()+" - "+p.getScore()+" points");
			cpt++;
		}
		System.out.print("\n");
	    break;
	    
	// +----------------------------------------------------------------------+
	// | menu PLAY : 5
	// |
	// | Quitter
	// +----------------------------------------------------------------------+
	case 5:
	    _service.logout(this.hashCode() + "", p);
	    System.out.println("Aurevoir et à bientôt !");
	    System.exit(0);
	    return -1;
	    
	//TODO dans quel cas ? message specifique ?
	default:
	    System.out.println("Saisie incorrecte!");
	    return _Config.MENU_PLAY;
	}
    } catch (RemoteException e) {
	System.out.println("Le serveur est inaccessible ou la requête est erronée");
	e.printStackTrace();
    }
    return menu;
    } 
    
    /**
     * 
     * @return numéro du prochain menu à afficher
     */
    private int menuParty() {
    int menu = _Config.MENU_PARTY;
    try {
	BufferedReader keyboard = new BufferedReader(new InputStreamReader(System.in));
	boolean arret = false;

	switch (sousMenu) {

	// +----------------------------------------------------------------------+
	// | menu PARTY : 1
	// |
	// | Jouer une carte
	// +----------------------------------------------------------------------+
	case 1:
        	System.out.println("***Jouer une carte***");
        	//TODO lui lister ses cartes
        	while (!arret) {
        	    System.out.println("Carte à jouer : "); try { nb = keyboard.readLine(); } catch (IOException e) { System.out.println("500 Internal Error"); }
        	    try {
        		num = Integer.parseInt(nb);
        		if(num > 1 && num < 32){
        		    //TODO jouer la carte + wait callback
        		    menu = _Config.MENU_PARTY;
        				
        		} else {
        		    System.out.println("Veuillez saisir un nombre valide");
        		}
        	     } catch (Exception e) {
        		 e.printStackTrace();
        		 System.out.println("Veuillez saisir un entier");
        	     }
        	}
	break;
		    
	// +----------------------------------------------------------------------+
	// | menu PARTY : 2
	// |
	// | Abandonner la partie
	// +----------------------------------------------------------------------+
	case 2:
	    System.out.println("***Abandonner la partie***");
	    while (!arret) {
    	    	System.out.println("Abandonner ? (O/N) : "); try { nb = keyboard.readLine(); } catch (IOException e) { System.out.println("500 Internal Error"); }
    	    	if(nb.contentEquals("O") || nb.contentEquals("o")){
    	    	    _service.quitterParty(party, p);
    	    	    menu = _Config.MENU_PLAY;
    	    	    arret = true;
    	    	} else if(nb.contentEquals("N") || nb.contentEquals("n")) {
    	    	    menu = _Config.MENU_PARTY;   
    	    	    arret = true;
    	    	}
	    }
	    break;
	
	default:
	    //Ca n'est pas censé arriver
	    break;
	}
    } catch (Exception e) {
	System.out.println("Le serveur est inaccessible ou la requête est erronée");
	e.printStackTrace();
    }
    return menu;
    }
    
    //+----------------------------------------------------------------------+
    //| 
    //| Reverse Proxy 
    //| 
    //+----------------------------------------------------------------------+
    public User() { }
    
    public User init(Tier2.RMI_PartyManager.PartyManager serviceRMI,
	    Tier2.ORB_PartyManager.PartyManager serviceIIOP, User.Callback callback) {
	_service = new Service(serviceRMI, serviceIIOP);
	_callback = callback;
	return this;
    }
    
    public class Callback {
	synchronized public void say(String msg) {
	    System.out.println(msg);
	    this.notifyAll();
	}
    }
    public class Service {
	private Tier2.RMI_PartyManager.PartyManager _serviceRMI = null;
	private Tier2.ORB_PartyManager.PartyManager _serviceIIOP = null;
	    
	public Service(Tier2.RMI_PartyManager.PartyManager serviceRMI, 
		Tier2.ORB_PartyManager.PartyManager serviceIIOP) {
		_serviceRMI = serviceRMI;
		_serviceIIOP = serviceIIOP;
	}
	
	public boolean login(String name, String password) throws RemoteException {
	    if(_serviceIIOP!=null) { return _serviceIIOP.login(name, password); }
	    else { return _serviceRMI.login(name, password); }
	}
	
	public Player getPlayer(String callback, String name) throws RemoteException {
	    if(_serviceIIOP!=null) { try {
		return Player.deserialize(_serviceIIOP.getPlayer(callback, name));
	    } catch (Exception e) {
		System.out.println("Cast error");
		e.printStackTrace();
	    } }
	    else { return _serviceRMI.getPlayer(callback, name); }
	    return null;
	}
	
	public boolean creerCompte(String name, String password) throws RemoteException {
	    if(_serviceIIOP!=null) { return _serviceIIOP.creerCompte(name, password); }
	    else { return _serviceRMI.creerCompte(name, password); }
	}
	
	public Party createParty(Player player, int nb_joueurs) throws RemoteException {
	    if(_serviceIIOP!=null) { try {
		return Party.deserialize(_serviceIIOP.createParty(Player.serialize(player), nb_joueurs));
	    } catch (Exception e) {
		System.out.println("Cast error");
		e.printStackTrace();
	    } }
	    else { return _serviceRMI.createParty(player, nb_joueurs); }
	    return null;
	}
	
	public ArrayList<Party> getParties() throws RemoteException {
	    if(_serviceIIOP!=null) { try {
		return Parties.deserialize(_serviceIIOP.getParties()).liste;
	    } catch (Exception e) {
		System.out.println("Cast error");
		e.printStackTrace();
	    } }
	    else { return _serviceRMI.getParties(); }
	    return null;
	}
	
	public Party joinParty(int hashParty, Player player) throws RemoteException { 
	    if(_serviceIIOP!=null) { try {
		return Party.deserialize(_serviceIIOP.joinParty(hashParty, Player.serialize(player)));
	    } catch (Exception e) {
		System.out.println("Cast error");
		e.printStackTrace();
	    } }
	    else { return _serviceRMI.joinParty(hashParty, player); }
	    return null;
	}
	
	public Players getClassement() throws RemoteException {
	    if(_serviceIIOP!=null) { try {
		return Players.deserialize(_serviceIIOP.getClassement());
	    } catch (Exception e) {
		System.out.println("Cast error");
		e.printStackTrace();
	    } }
	    else { return _serviceRMI.getClassement(); }
	    return null;
	}
	
	public void logout(String user, Player player) throws RemoteException {
	    if(_serviceIIOP!=null) { try {
		_serviceIIOP.logout(user, Player.serialize(player));
	    } catch (Exception e) {
		System.out.println("Cast error");
		e.printStackTrace();
	    } }
	    else { _serviceRMI.logout(user, player); }
	}
	
	public void quitterParty(Party party, Player player) throws RemoteException {
	    if(_serviceIIOP!=null) { try {
		_serviceIIOP.quitterParty(Party.serialize(party), Player.serialize(player));
	    } catch (Exception e) {
		System.out.println("Cast error");
		e.printStackTrace();
	    } }
	    else { _serviceRMI.quitterParty(party, player); }
	}
    }
}
